package net.lgy.util;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.security.Keys;
import net.lgy.dto.AccountDTO;


import java.security.Key;
import java.util.Date;

/**
 * JWT工具类，用于生成、解析和验证JWT令牌
 * JWT (JSON Web Token) 是一种基于JSON的开放标准，用于在各方之间安全地传输信息
 * 本工具类提供了生成token和校验token的核心功能
 */
@lombok.extern.slf4j.Slf4j
public class JWTUtil {
    // 主题：用于标识JWT的用途或所属系统，通常设置为应用名称
    private static final String SUBJECT = "lgy-cloud";

    // 加密密钥：用于签名JWT的密钥，必须保密且强度足够，防止被破解
    // 生产环境中建议使用更复杂的密钥，并通过配置文件注入
    private static final String SECRET = "lgy-cloud.site";

    // token前缀：用于在HTTP请求头中标识JWT令牌，便于服务端识别
    // 通常在请求头中使用 "Authorization: token-link <token>" 形式
    private static final String TOKEN_PREFIX = "token-link";

    // 过期时间：令牌的有效期，此处设置为一周（单位：毫秒）
    // 1000ms * 60s * 60min * 24h * 7d = 604800000ms
    private static final long EXPIRED = 1000 * 60 * 60 * 24 * 7;




    /**
     * 生成JWT令牌
     * 根据登录用户信息生成包含用户基本信息的加密令牌
     *
     * @param loginUser 登录用户对象，包含需要存入token的用户信息
     * @return 生成的完整JWT令牌（包含前缀）
     * @throws NullPointerException 如果loginUser为null则抛出空指针异常
     */
    public static String geneJsonWebToken(AccountDTO loginUser){
        // 校验输入参数，确保用户对象不为空
        if (loginUser == null){
            throw new NullPointerException("登录用户对象为空，无法生成token");
        }

        // 使用Jwts构建器生成token
        String token = Jwts.builder()
                // 设置主题（与类中定义的SUBJECT一致）
                .setSubject(SUBJECT)
                // 向token中添加自定义声明（用户头像）
                .claim("head_img", loginUser.getHeadImg())
                // 向token中添加自定义声明（用户名）
                .claim("username", loginUser.getUsername())
                // 向token中添加自定义声明（邮箱）
                .claim("mail", loginUser.getMail())
                // 向token中添加自定义声明（手机号）
                .claim("phone", loginUser.getPhone())
                // 向token中添加自定义声明（权限信息）
                .claim("auth", loginUser.getAuth())
                .claim("account_no",loginUser.getAccountNo())
                // 设置token签发时间（当前时间）
                .setIssuedAt(new Date())
                // 设置token过期时间（当前时间 + 有效期）
                .setExpiration(new Date(CommonUtil.getCurrentTimestamp() + EXPIRED))
                // 设置签名算法和签名密钥（使用HS256算法）
                .signWith(SignatureAlgorithm.HS256, SECRET)
                // 压缩为最终的token字符串
                .compact();

        // 为token添加前缀，便于后续识别和解析
        token = TOKEN_PREFIX + token;
        return token;
    }


    /**
     * 校验并解析JWT令牌
     * 验证token的有效性并提取其中的声明信息
     *
     * @param token 待校验的JWT令牌（包含前缀）
     * @return 解析后的Claims对象，包含token中的所有声明信息；如果校验失败返回null
     */
    public static Claims checkJWT(String token) {
        try {
            // 生成签名密钥（需与生成token时的密钥一致，这里演示简单字符串生成，实际建议用Keys生成安全密钥）
            Key signingKey = Keys.hmacShaKeyFor(SECRET.getBytes());

            // 使用 parserBuilder 构建解析器（新版JJWT推荐用法）
            Claims claims = Jwts.parser()
                    .setSigningKey(signingKey) // 设置签名密钥
                    .build()
                    // 移除token前缀后解析
                    .parseClaimsJws(token.replace(TOKEN_PREFIX, ""))
                    .getBody();
            return claims;
        } catch (Exception e) {
            // 捕获所有可能的异常（包括签名错误、过期、格式错误等）
            System.err.println("JWT令牌校验失败，错误信息：" + e.getMessage());
            return null;
        }
    }

}